#pragma once
#include "../file/file_manager.h"

class CImage
{
protected:
	unsigned char *_data;
	unsigned char _bpp;
	int _width, _height;
public:
	CImage():_data(NULL), _bpp(0), _width(0), _height(0){}
	~CImage(){}
	const unsigned char* getData() const {return _data;}
	int getWidth() const {return _width;}
	int getHeight() const {return _height;}
	unsigned char getBpp() const {return _bpp / 8;}
	virtual int load(const char* filename) = 0;
};

/*
start  	size  	name  	stdvalue  	purpose
1  	2  	bfType			19778  	must always be set to 'BM' to declare that this is a .bmp-file.
3 	4 	bfSize			?? 	specifies the size of the file in bytes.
7 	2 	bfReserved1		0	must always be set to zero.
9 	2 	bfReserved2		0	must always be set to zero.
11 	4 	bfOffBits		1078	specifies the offset from the beginning of the file to the bitmap data.

15	4 	biSize			40	specifies the size of the BITMAPINFOHEADER structure, in bytes.
19 	4	biWidth			100	specifies the width of the image, in pixels.
23 	4 	biHeight		100	specifies the height of the image, in pixels.
27 	2 	biPlanes		1	specifies the number of planes of the target device, must be set to zero.
29 	2 	biBitCount		8	specifies the number of bits per pixel.
31 	4 	biCompression	0	Specifies the type of compression, usually set to zero (no compression).
35 	4 	biSizeImage		0	specifies the size of the image data, in bytes. If there is no compression, it is valid to set this member to zero.
39 	4 	biXPelsPerMeter	0	specifies the the horizontal pixels per meter on the designated targer device, usually set to zero.
43 	4 	biYPelsPerMeter	0	specifies the the vertical pixels per meter on the designated targer device, usually set to zero.
47 	4 	biClrUsed		0	specifies the number of colors used in the bitmap, if set to zero the number of colors is calculated using the biBitCount member.
51 	4 	biClrImportant 	0	specifies the number of color that are 'important' for the bitmap, if set to zero, all colors are important.

BYTE	hdr[54];
RGBQUAD	aColors[];
BYTE	aBitmapBits[];

*/

class CBitmapImage : public CImage
{
private:
	unsigned char *_pixels;
	inline unsigned short _bfType(void){return *((unsigned short *)_data);};
	inline unsigned int _bfSize(void){return *((unsigned int *)(_data + 2));};
	inline unsigned int _bfReserved(void){return *((unsigned int *)(_data + 6));};
	inline unsigned short _bfOffBits(void){return *((unsigned short *)(_data + 10));};
	/**/
	inline unsigned int _biSize(void){return *((unsigned int *)(_data + 14));};
	inline unsigned int _biWidth(void){return *((unsigned int *)(_data + 18));};
	inline unsigned int _biHeight(void){return *((unsigned int *)(_data + 22));};
	inline unsigned short _biPlanes(void){return *((unsigned short *)(_data + 26));};
	inline unsigned short _biBitCount(void){return *((unsigned short *)(_data + 28));};
	inline unsigned int _biCompression(void){return *((unsigned int *)(_data + 30));};
	inline unsigned int _biSizeImage(void){return *((unsigned int *)(_data + 34));};
	inline unsigned int _biXPelsPerMeter(void){return *((unsigned int *)(_data + 38));};
	inline unsigned int _biYPelsPerMeter(void){return *((unsigned int *)(_data + 42));};
	inline unsigned int _biClrUsed(void){return *((unsigned int *)(_data + 46));};
	inline unsigned int _biClrImportant(void){return *((unsigned int *)(_data + 50));};

public:
	CBitmapImage(void):_pixels(NULL){}
	~CBitmapImage(void){}

	int load(const char* filename)
	{
		if ((_data = io::CFileManager::getInstance()->getRawData(filename)) != NULL)
		{
			_bpp = (unsigned char) _biBitCount();
			_width = _biWidth();
			_height = _biHeight();
			_pixels = _data + _bfOffBits();

			// Photoshop's ARGB to OpenGL RGBA conversion ...
			for (int i = 0; i < _width * _height * 4; i += 4)
			{
				unsigned char alpha = _pixels[i + 3];
				unsigned char red = _pixels[i + 2];
				unsigned char green = _pixels[i + 1];
				unsigned char blue = _pixels[i + 0];
				alpha = 0xff;
				_pixels[i] = blue; //output - blue
				_pixels[i + 1] = alpha; //output - alpha
				_pixels[i + 2] = red; //output - red
				_pixels[i + 3] = green; // //output - green
			}

			return TRUE;
		}
		return FALSE;
	};
	void unload(){delete _data;};
	unsigned char operator() (unsigned int r, unsigned int c) const
	{
		unsigned int d = _bpp;// / 8;
		return *(_pixels + (r * _width * d + c * d));
	};
};